import os
import re
import time
import datetime
import gtk
import gtk.glade
import pango
from BuildWizException import BuildWizException
from Preferences import Preferences
from PlatformHelper import PlatformHelper
from OutputWindow import OutputWindow
from FileConfigurator import FileConfigurator 
from DlgFileSelection import DlgFileSelection
from BuildExecutor import BuildExecutor

class BuildWizard():
    def __init__( self, preferences = Preferences):
        if type( preferences) != type( Preferences()):
            raise BuildWizException( "BuildWizard expects a Preferences instance as parameter")

        self.pref = preferences
        self.logDir = self.pref.getLogDir() 
        self.platformFiles = self.__scanPlatformDir()
        self.platforms = {}
        self.builders = {}
        self.__knownCMakeVars = {}
        self.outputWins = {}
        self.buildTags = { "start": "__start__"
                         , "before": "__before__"
                         , "cd": "__cd_build_dir__"
                         , "cmake": "__cmake__"
                         , "make": "__make__"
                         , "install": "__make_install"
                         , "after": "__script_after__"
                         , "end": "__end__" }
        self.datetimeFrmt = self.pref.getDateTimeFormat4Logs()
        self.__cmakeVarTypes = [ 'STRING', 'BOOLEAN', 'INTEGER']
        self.__readKnownCMakeVars()
        self.outputWinFile = self.pref.getGUIFile( "outputwindow")
        for item in self.platformFiles:
            platf = PlatformHelper( item)
            self.platforms[ platf.getID()] = platf
    
    def setMainWindow( self, mainwin):
        self.__mainWin = mainwin

    def __readKnownCMakeVars( self):
        cvf = self.pref.getFileOfCMakeVars()
        try:
            fd = open( cvf, 'r')
            for line in fd.readlines():
                line = line.rstrip( "\n")
                if line[:1] != '#':
                    self.__processLine( line)
        except IOError, e:
            print e

    def __processLine( self, line):
        varname, vartype = line.split( ':')
        if len( varname) and (vartype in self.__cmakeVarTypes):
            self.__knownCMakeVars[ varname] = vartype

    def getCMakeKnownVariables( self):
        return self.__knownCMakeVars

    def getPlatforms( self):
        return self.platforms

    def getPreferences( self):
        return self.pref

    def getPlatformsDir( self):
        return self.pref.getPlatformDir()

    def __scanPlatformDir( self):
        platfDir = self.pref.getPlatformDir()
        entries = os.listdir( platfDir)
        platforms = []
        for filename in entries:
            if filename[-4:] == '.cfg':
                platforms.append( os.path.join( platfDir, filename))
        return platforms

    def getPlatformsToBuild( self):
        self.platfReadyToBuild = []
        for platf in self.platforms.values():
            if platf.isWaiting4Build():
                if self.__validatePlatformStatus( platf):
                    self.platfReadyToBuild.append( platf.getID())

        return self.platfReadyToBuild
                

    def __validatePlatformStatus( self, platf):
        # TODO: Make something interesting with this type of status as to
        # provide rich information to the user about what has happened
        # with previous execution...
        # For now let's just change blindly the status...
        # 
        if platf.getStatus() != "STATUS_BUILD_IN_PROGRESS":
            platf.setStatus( "STATUS_READY_TO_BUILD")
            return True
        else:
            return False
            
    def getPlatformStatus( self, platfname):
        if self.platforms.has_key( platfname):
            return self.platforms[ platfname].getStatus()
        return ""

    def getPlatformsBuildInProgress( self):
        platfInBuildProcess = []
        # The platforms in running process are the same in
        # the self.platfReadyToBuild - of course with another status
        for platfName in self.platfReadyToBuild:
            if self.platforms[ platfName].getStatus() == 'STATUS_BUILD_IN_PROGRESS':
                platfInBuildProcess.append( platfName)

        return platfInBuildProcess

    def getPlatformConfigVariables( self, platfName):
        try:
            self.__vars = self.platforms[ platfName].getAllVariables()
        except KeyError, e:
            raise BuildWizException( "BuildWizard.getPlatformConfigVariables() : unknown platform [%s]" % platfName)
        return self.__vars

    def runCMake( self):
        self.builders.clear()
        #self.outputWins.clear()
        for platfName in self.platfReadyToBuild:
            scriptBefore = ""
            if self.platforms[ platfName].getRunScriptBefore():
                 scriptBefore = self.platforms[ platfName].getScriptBefore()

            scriptAfter = ""
            if self.platforms[ platfName].getRunScriptAfter():
                scriptAfter = self.platforms[ platfName].getScriptAfter()

            command = self.platforms[ platfName].getCMakeCommand()
            buildDir = self.platforms[ platfName].getBuildDir()
            runMakeInstall = self.platforms[ platfName].isRunMakeInstall()
            numJobs = self.platforms[ platfName].getNumMakeJobs()
            
            if not self.outputWins.has_key( platfName):
                self.outputWins[ platfName] = OutputWindow( self.outputWinFile, platfName, self)
            else:
                self.outputWins[ platfName].clear()

            self.builders[ platfName] = BuildExecutor( buildDir
                                                     , self.platforms[ platfName]
                                                     , command
                                                     , scriptBefore
                                                     , scriptAfter
                                                     , self.outputWins[ platfName]
                                                     , runMakeInstall
                                                     , numJobs
                                                     , self.platforms[ platfName].getBuildFileName2Log( self.logDir)
                                                     , self)
            self.outputWins[ platfName].show()
            self.builders[ platfName].start()

        return

    def stopBuilder( self, platfName):
        if self.builders.has_key( platfName):
            if self.builders[ platfName].isAlive():
                self.builders[ platfName].join( 1.0)
           
            del( self.builders[ platfName])
        else:
            print "BuildWizard.stopBuilder() - there is no builder for this platform"

    def stopBuilders( self, buildersName):
        for buildername in buildersName:
            self.stopBuilder( buildername)

    def stopAllBuilders( self):
        for platfName in self.getPlatformsBuildInProgress():
            self.stopBuilder( platfName)
            if self.outputWins.has_key( platfName):
                self.outputWins[ platfName].notifyOuterStop()

    def shutdown( self):
        return 

    def addPlatformVariable( self, platfname, newVar):
        if self.platforms.has_key( platfname):
            try:
                isCMakeVar = newVar.getName() in self.__knownCMakeVars.keys()
                if isCMakeVar:
                    newVar.setAsCMakeVar()
                self.platforms[ platfname].addVariable( newVar)
            except BuildWizException, e:
                raise e
        else:
            raise BuildWizException( "unknow platform [" + platfname + "]")

    def delPlatformVariable( self, platfname, varname):
        if self.platforms.has_key( platfname):
            self.platforms[ platfname].delVariable( varname)
        
    def setConfigVar( self, platfname, varname, vartype, varvalue):
        if platfname in self.platforms:
            self.platforms[ platfname].setVariable( varname, vartype, varvalue)

    def saveConfiguration( self, platfname):
        self.platforms[ platfname].saveConfigs()

    def setRunMakeInstall( self, platfname, runMakeInstall):
        print "setRunMakeInstall = ", platfname
        self.platforms[ platfname].setRunMakeInstall( runMakeInstall)

    def setNumMakeJobs( self, platfname, numJobs):
        self.platforms[ platfname].setNumMakeJobs( numJobs)

    def getNumMakeJobs( self, platfname):
        return self.platforms[ platfname].getNumMakeJobs()

    def getRunMakeInstall( self, platfname):
        return self.platforms[ platfname].isRunMakeInstall()

    def getScriptBefore( self, platfname):
        return self.platforms[ platfname].getScriptBefore()

    def getScriptAfter( self, platfname):
        return self.platforms[ platfname].getScriptAfter()

    def setScriptBefore( self, platfname, file):
        self.platforms[ platfname].setScriptBefore( file)

    def setScriptAfter( self, platfname, file):
        self.platforms[ platfname].setScriptAfter( file)

    def setRunScriptBefore( self, platfname, runOrNot):
        self.platforms[ platfname].setRunScriptBefore( runOrNot)

    def getRunScriptBefore( self, platfname):
        return self.platforms[ platfname].getRunScriptBefore()

    def setRunScriptAfter( self, platfname, runOrNot):
        self.platforms[ platfname].setRunScriptAfter( runOrNot)

    def getRunScriptAfter( self, platfname):
        return self.platforms[ platfname].getRunScriptAfter()

    def getAboutInfo( self):
        return self.pref.getAboutInfo()

    def setPlatformDescription( self, platfname, descr):
        self.platforms[ platfname].setDescription( descr)

    def getPlatformDescription( self, platfname):
        return self.platforms[ platfname].getDescription()

    def getPlatformProjectDir( self, platfname):
        return self.platforms[ platfname].getProjectDir()

    def setPlatformProjectDir( self, platfname, dir):
        self.platforms[ platfname].setProjectDir( dir)

    def getPlatformCmakeListsDir( self, platfname):
        return self.platforms[ platfname].getCMakeListsDir()

    def setPlatformCmakeListsDir( self, platfname, dir):
        self.platforms[ platfname].setCMakeListsDir( dir)

    def getPlatformBuildDir( self, platfname):
        return self.platforms[ platfname].getBuildDir()

    def setPlatformBuildDir( self, platfname, dir):
        self.platforms[ platfname].setBuildDir( dir)

    def reloadPlatform( self, platfname):
        self.platforms[ platfname].reloadFile()

    def setPlatformVerifySubvUpdates( self, platfname, verifyOrNot):
        self.platforms[ platfname].setVerifySubversionUpdates( verifyOrNot)

    def isPlatformWorkingCopy( self, platfname):
        return self.platforms[ platfname].isWorkingCopy()

    def isPlatformVerifySubversionUpdates( self, platfname):
        return self.platforms[ platfname].isVerifySubversionUpdates()
        
    def getPlatformSubversionURL( self, platfname):
        return self.platforms[ platfname].getSubversionURL()

    def getPlatformSubversionRevision( self, platfname):
        return self.platforms[ platfname].getSubversionRevision()

    def setPlatformSubversionURL( self, platfname, url):
        self.platforms[ platfname].setSubversionURL( url)

    def setPlatformSubversionRevision( self, platfname, revision):
        self.platforms[ platfname].setSubversionRevision( int( revision))

    def saveNewPlatform( self, values):
        if values[ "file"] not in self.platformFiles:
            try:
                fc = FileConfigurator( values)
                platf = PlatformHelper( values[ "file"])
                self.platforms[ platf.getID()] = platf
                self.__mainWin.addPlatform( platf)
            except BuildWizException, e:
                print "BuildWizard.saveNewPlatform: " + e.getStrError()

    def deletePlatform( self, platfname):
        if self.platforms.has_key( platfname):
            f = self.platforms[ platfname].getConfigFileName()
            if os.path.isfile( f):
                os.remove( f)
            sb = self.platforms[ platfname].getScriptBefore()
            if os.path.isfile( sb):
                os.remove( sb)
            sa = self.platforms[ platfname].getScriptAfter()
            if os.path.isfile( sa):
                os.remove( sa)

            del( self.platforms[ platfname])
            
            if self.outputWins.has_key( platfname):
                self.outputWins[ platfname].destroy()
                del( self.outputWins[ platfname])

            if self.builders.has_key( platfname):
                del( self.builders[ platfname])
            
        else:
            dlg = gtk.MessageDialog( None, 0, gtk.MESSAGE_ERROR,
                    gtk.BUTTONS_OK, "Ooops - internal error!!!\nNo platform [" + platfname + "] found to be deleted.")
            dlg.run()
            dlg.destroy()
 
    def getDeployPenValues( self, platfname):
        settings = {}
        if self.platforms.has_key( platfname):
            settings = self.platforms[ platfname].getDeployPenValues()
        return settings

    def setDeployPenValues( self, platfname, values):
        if self.platforms.has_key( platfname):
            self.platforms[ platfname].setDeployPenValues( values)

    def getDeployInfo( self, platfname):
        if self.platforms.has_key( platfname):
            return self.platforms[ platfname].getDeployInfo()

    def setFontOutput( self, platfname, fontname):
        if self.platforms.has_key( platfname):
            self.platforms[ platfname].setFontOutput( fontname)

    def getFontOutput( self, platfname):
        if self.platforms.has_key( platfname):
            return self.platforms[ platfname].getFontOutput()
        return ""
